package cn.wjssl.domain.strategy.service.rule.tree.factory.engine.impl;

import cn.wjssl.domain.strategy.model.valobj.RuleLogicCheckTypeVO;
import cn.wjssl.domain.strategy.model.valobj.RuleTreeNodeLineVO;
import cn.wjssl.domain.strategy.model.valobj.RuleTreeNodeVO;
import cn.wjssl.domain.strategy.model.valobj.RuleTreeVO;
import cn.wjssl.domain.strategy.service.rule.tree.ILogicTreeNode;
import cn.wjssl.domain.strategy.service.rule.tree.factory.DefaultTreeFactory;
import cn.wjssl.domain.strategy.service.rule.tree.factory.engine.IDecisionTreeEngine;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 决策引擎实现类, 实现决策树链过滤
 */
@Slf4j
public class DecisionTreeEngine implements IDecisionTreeEngine {

    private final RuleTreeVO ruleTreeVO;
    private final Map<String, ILogicTreeNode> logicMap;

    // 因为需要传入参数, 所以不能用@Resource, 需要构造器注入
    public DecisionTreeEngine(Map<String, ILogicTreeNode> logicMap, RuleTreeVO ruleTreeVO) {
        this.ruleTreeVO = ruleTreeVO;
        this.logicMap = logicMap;
    }

    @Override
    public DefaultTreeFactory.StrategyAwardVO logicTree(String userId, Long strategyId, Integer awardId, Date endDateTime) {

        // 初始化奖品对象
        DefaultTreeFactory.StrategyAwardVO strategyAwardVO = null;
        // 获取根节点的rule_key, 与决策树的所有节点map
        String nextNodeRuleKey = ruleTreeVO.getTreeRootRuleNodeRuleKey();
        Map<String, RuleTreeNodeVO> nodeVOMap = ruleTreeVO.getTreeNodeMap();
        // 根据根节点的rule_key, 获得根节点
        RuleTreeNodeVO nodeVO = nodeVOMap.get(nextNodeRuleKey);
        // 进行节点过滤
        while (nextNodeRuleKey != null) {
            // 获取节点对应的过滤器
            ILogicTreeNode logicNode = logicMap.get(nodeVO.getRuleKey());
            // 获取过滤行为对象
            DefaultTreeFactory.TreeActionEntity treeActionEntity = logicNode.logicTree(userId, strategyId, awardId, nodeVO.getRuleValue(), endDateTime);
            RuleLogicCheckTypeVO ruleLogicCheckTypeVO = treeActionEntity.getRuleLogicCheckType();
            // 获取当前过滤节点的奖品流转对象
            strategyAwardVO = treeActionEntity.getStrategyAwardVO();
            log.info("决策树引擎【{}】treeId:{} node:{} code:{}", ruleTreeVO.getTreeName(), ruleTreeVO.getTreeId(), nextNodeRuleKey, ruleLogicCheckTypeVO.getCode());
            // 从连线中, 获取下个过滤节点
            nextNodeRuleKey = nextNode(ruleLogicCheckTypeVO.getCode(), nodeVO.getTreeNodeLineVOList());
            nodeVO = nodeVOMap.get(nextNodeRuleKey);
        }
        // 如果没有下一个节点了, 那就返回当前节点的奖品流转对象
        return strategyAwardVO;
    }

    // 获取下一个节点key的方法
    public String nextNode(String matterValue, List<RuleTreeNodeLineVO> treeNodeLineVOList) {
        // 如果树节点的链表是空的, 那说明没有下一个节点了, 直接返回null
        if (null == treeNodeLineVOList || treeNodeLineVOList.isEmpty()) return null;
        // 循环决策树链表, 获取链表
        for (RuleTreeNodeLineVO nodeLine : treeNodeLineVOList) {
            // 如果是要导入下一个节点
            if (decisionLogic(matterValue, nodeLine)) {
                // 那就返回下一个节点的 ruleKey]指向
                return nodeLine.getRuleNodeTo();
            }
        }
        // 找不到不需要抛异常, 有可能就是没有下一个过滤器了, 直接返回null即可
        return null;
    }

    // 对决策链表是否要导入下一个节点 进行判断
    public boolean decisionLogic(String matterValue, RuleTreeNodeLineVO nodeLine) {
        switch (nodeLine.getRuleLimitType()) {
            case EQUAL:
                // RuleLimitValue 规则树节点指向线。用于衔接 from->to 节点链路关系
                return matterValue.equals(nodeLine.getRuleLimitValue().getCode());
            // 以下规则暂时不需要实现
            case GT:
            case LT:
            case GE:
            case LE:
            default:
                return false;
        }
    }
}
